home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / Communication / MailHelper / Source / Controller.m < prev    next >
Encoding:
Text File  |  1993-09-13  |  11.7 KB  |  430 lines

  1. /* Controller.m -- Controller object for MailHelper application.
  2.    Copyright 1991, Izumi Ohzawa and Manuel Alberto Ricart, All rights reserved.
  3.    3-17-91  V1.0 (IO)
  4.     * Starting project.
  5.     * Some codes are borrowed from AtYourService NeXT demo application.
  6.    4-6-91   V1.0 (IO)
  7.     * Bug fix: fclose(fpin); was missing in method insertSignature.
  8.    9-18-91  V1.1 (MAR)
  9.     * Preferences panel and use of default database to store them.
  10.         Joint venture with Izumi? Perhaps.    Izumi sent me his code
  11.         for MailHelper.  I told him I implement some basic prefs for him.
  12.    9-22-91  V1.1 (IO)
  13.     * Defaults now written out as soon as OK button in Pref panel is pressed.
  14.     * Signature insertion now adds a separator '---' within the code to
  15.         remove requirement of having it in signature file itself (to make MailHelper
  16.         conform with other programs which use .signature).
  17.     * RTF signature insertion added.
  18.     
  19.   10-9-91  V1.2 (Mitsuhiro Kishimoto)
  20.     * Japanese re-format routine: needed to handle mixed ASCII and 2-byte EUC code.
  21.         Original "Kin-soku" (forbidden line break) code was written
  22.         by Masatoshi Kurihara.
  23.         
  24.   9-10-93 V1.3 Mike O'Neill (emo@mitre.org) added .rtfd support, grayed rtf selection, and 3.0 colorized icon and compiled FAT
  25.  
  26.    To implement:
  27.    User selectable command keys for various functions.
  28. */
  29.  
  30.  
  31. #import "Controller.h"
  32. #import <appkit/appkit.h>
  33.  
  34.  
  35. @implementation Controller
  36.  
  37. /* Modified Izumi's code to load the defaults at startup.
  38.  * It also sets up the default values on the prefs panel.
  39. */
  40. - appDidInit:sender
  41. {
  42.     static NXDefaultsVector MailHelperDefaults = {
  43.         {WIDTH,"62"},
  44.         {QUOTE,"> "},
  45.         {SIGFILE,SIGFILENAME},
  46.         {RTFSIGFILE,RTFSIGFILENAME},
  47.         {RTFDSIGFILE,RTFDSIGFILENAME},
  48.         {NULL}
  49.     };
  50.     myListener = [NXApp appListener];
  51.     [myListener setServicesDelegate: self];
  52.     
  53.     NXRegisterDefaults(APPNAME, MailHelperDefaults);
  54.     wrapWidth = atoi(NXGetDefaultValue(APPNAME, WIDTH));
  55.     [gWrapWidth setIntValue:wrapWidth];
  56.     [gWrapScroller setIntValue:wrapWidth];
  57.     quoteString =(char *) NXGetDefaultValue(APPNAME, QUOTE);
  58.     [gQuoteString setStringValue:quoteString];
  59.     sigFile =(char *) NXGetDefaultValue(APPNAME, SIGFILE);
  60.     [gSigFileName setStringValue:sigFile];
  61.     rtfSigFile =(char *) NXGetDefaultValue(APPNAME, RTFSIGFILE);
  62.     [gRtfSigFileName setStringValue:rtfSigFile];    
  63.     rtfdSigFile =(char *) NXGetDefaultValue(APPNAME, RTFDSIGFILE);
  64.     [gRtfdSigFileName setStringValue:rtfdSigFile];
  65. //    [gRtfdText setGraphicsImportEnabled:YES];
  66.     return self;
  67. }
  68.  
  69.     
  70.  
  71. /* Brings up the Info panel.   Not done on startup because it's in a separate
  72.  * interface file. Saves startup time for the user if we do this when they ask
  73.  * for it, and not before.
  74.  * "infoPanel" and "helpPanel" are defined in "Info.nib".
  75.  */
  76. - infoPanel:sender
  77. {
  78.     if( ! infoPanel ){
  79.     [NXApp loadNibSection:"Info.nib" owner:self];
  80.     }
  81.     [infoPanel makeKeyAndOrderFront:sender];
  82.     return self;    
  83. }
  84.  
  85. // Records the prefsPanel values into the global variables
  86. /* [izumi] Moved from delegate method -appWillTerminate:, because it is
  87.  * not apparently called if user is logging out from Workspace --
  88.  * this is how MailHelper gets terminated (MailHelper is almost never
  89.  * exited via Quit from menu.).
  90. */
  91. - prefsOK:sender
  92. {
  93.    char buf[20];
  94.     wrapWidth = (int)[gWrapWidth intValue];
  95.     quoteString = (char *)[gQuoteString stringValue];
  96.     sigFile = (char *)[gSigFileName stringValue];    
  97.     rtfSigFile = (char *)[gRtfSigFileName stringValue];    
  98.  
  99.     sprintf(buf, "%d", wrapWidth);
  100.     NXWriteDefault(APPNAME, WIDTH, buf);
  101.     NXWriteDefault(APPNAME, QUOTE, quoteString);
  102.     NXWriteDefault(APPNAME, SIGFILE, sigFile);
  103.     NXWriteDefault(APPNAME, RTFSIGFILE, rtfSigFile);
  104.     return self;    
  105. }
  106.  
  107. - prefsCancel:sender
  108.     [gWrapWidth setIntValue:wrapWidth];
  109.     [gWrapWidth display];
  110.     [gWrapScroller setIntValue:wrapWidth];
  111.     [gWrapScroller display];
  112.     [gQuoteString setStringValue:quoteString];
  113.     [gQuoteString display];
  114.     [gSigFileName setStringValue:sigFile];
  115.     [gSigFileName display];
  116.     [gRtfSigFileName setStringValue:rtfSigFile];
  117.     [gRtfSigFileName display];
  118.     
  119.     return self;
  120. }
  121. /*
  122.  * Brings up the Help panel (as above)
  123.  */
  124. - helpPanel:sender
  125. {
  126.     if( ! helpPanel ){
  127.     [NXApp loadNibSection:"Info.nib" owner:self];
  128.     }
  129.     [helpPanel makeKeyAndOrderFront:sender];
  130.     return self;    
  131.  
  132. }
  133.  
  134.  
  135.  
  136. /* Reformats selected text so that it fits into a specified column width.
  137.  * Alberto's Modifications:
  138.  * initialized colLimit to wrapWidth global variable.
  139. */
  140.  
  141. - reformatSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
  142. {
  143. char *data; 
  144. int   length;
  145. const char *const *types;
  146. int   hasAscii, i;
  147.  
  148.     types = [pbid types];        /* get a list of pasteboard types */
  149.     hasAscii = 0;
  150.     for(i=0; !hasAscii && types[i]; i++)
  151.         if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1;
  152.     if(hasAscii)
  153.     {
  154.         [pbid readType:NXAsciiPboardType data:&data length:&length];
  155.         if(data && length)
  156.         {
  157.         char *returnData, *dataptr, *endptr;
  158.         char *retptr;
  159.         int col;
  160.         unsigned char c1, c2;
  161.  
  162.         col = 0;
  163.         returnData=malloc(length+10);
  164.         dataptr = data;
  165.         endptr = dataptr+length;
  166.         retptr = returnData;
  167.  
  168.         while (dataptr < endptr) {
  169.             c1 = *dataptr++;
  170.             c2 = (iskanji (c1) ? *dataptr++ :  *dataptr);
  171.  
  172.             switch (c1) {
  173.                 case '\n':
  174.                     if ( c2 == '\n')
  175.                         col = 0;
  176.                     else if (iskanji (c2))
  177.                         goto skip_char;
  178.                     else
  179.                         c1 = ' ';
  180.                     break;
  181.                 case '\t':
  182.                     col = (col + 8) &~ 7;
  183.                     break;
  184.                 case '\b':
  185.                     col = col ? col - 1 : 0;
  186.                     break;
  187.                 default:
  188.                     col = col + (iskanji (c1) ? 2 : 1);
  189.             }
  190.             if (col > wrapWidth) {
  191.                 if ( ! iskanji (c1)) {
  192.                 for (i = 1; 0 < col - i; i++) {
  193.                     c2 = *(retptr - i);
  194.                     if ( iskanji (c2) ) {
  195.                         dataptr -= i;
  196.                         retptr -= (i - 1);
  197.                         *retptr++ = '\n';
  198.                         col = 0;
  199.                         goto skip_char;
  200.                     } else if ( isspace (c2) ) {
  201.                         dataptr -= i;
  202.                         retptr -= i;
  203.                         *retptr++ = '\n';
  204.                         col = 0;
  205.                         goto skip_char;
  206.                     }
  207.                 }
  208.                 *retptr++ = '\n';
  209.                 col = 1;
  210.                 } else if (iskanji (c1) &&  ! KINSOKU (c1, c2)) {
  211.                 *retptr++ = '\n';
  212.                 col = 2;
  213.                 }                
  214.             }
  215.             *retptr++= c1;
  216.             if (iskanji (c1))
  217.                 *retptr++= c2;
  218.             else if (c1 == '\n' &&  c2 == '\n') {
  219.                 *retptr++= c2;
  220.                 dataptr++;
  221.             }
  222.     skip_char:
  223.         ;
  224.         }
  225.         *retptr++= '\n';
  226.         *retptr = '\0';
  227.         [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
  228.         [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
  229.         free(returnData);
  230.         } /* end if(data && length) */
  231.         else
  232.         *errmsg = "Selection is empty.";
  233.     }  /* end if(hasAscii) */
  234.     else
  235.         *errmsg = "No ASCII text found in your selection.";
  236.     return self;
  237. }
  238.  
  239.  
  240.  
  241. /* Adds quotation marks "> " to the head of each line of selected text.
  242.  * Alberto's Modification:
  243.  * Only changed the definition of quotestr to point to the quoteString global.
  244. */
  245.  
  246. - quoteSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
  247. {
  248. char *data; 
  249. int   length;
  250. const char *const *types;
  251. char *quotestr = quoteString;
  252. int   hasAscii, i, quotelen;
  253.  
  254.     quotelen = strlen(quotestr);
  255.     types = [pbid types];        /* get a list of pasteboard types */
  256.     hasAscii = 0;
  257.     for(i=0; !hasAscii && types[i]; i++)
  258.         if(!strcmp(types[i], NXAsciiPboardType)) hasAscii = 1;
  259.     if(hasAscii)
  260.     {
  261.         [pbid readType:NXAsciiPboardType data:&data length:&length];
  262.         if(data && length)
  263.         {
  264.     int numlines;
  265.         char ch;
  266.     char *returnData, *dataptr, *endptr, *outptr;
  267.  
  268.         numlines = 1;
  269.         dataptr = data;          /* ptr to original data */
  270.         endptr = data+length;      /* ptr to end of data */
  271.         while(dataptr < endptr)      /* count the number of lines */
  272.             if(*dataptr++ == '\n')
  273.             numlines++;
  274.         returnData=malloc(length+numlines*quotelen+10);
  275.         dataptr = data;          /* reinitialize ptr to orig data */
  276.         outptr = returnData;
  277.         for(i=0;i<quotelen;i++)
  278.            *outptr++ = quotestr[i];
  279.         while(dataptr < endptr)
  280.         {
  281.             if((ch = *dataptr++) == '\n')
  282.             {
  283.             *outptr++ = ch;
  284.             for(i=0;i<quotelen;i++)
  285.                *outptr++ = quotestr[i];
  286.             }
  287.             else
  288.             *outptr++ = ch;
  289.         }
  290.         *outptr = '\n';
  291.         *(outptr+1) = '\0';
  292.         [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
  293.         [pbid writeType:NXAsciiPboardType data:returnData length:strlen(returnData)];
  294.         free(returnData);
  295.         } /* end if(data && length) */
  296.         else
  297.         *errmsg = "Selection is empty.";
  298.     }  /* end if(hasAscii) */
  299.     else
  300.         *errmsg = "No ASCII text found in your selection.";
  301.     return self;
  302. }
  303.  
  304.  
  305. // Adds the content of ~/.signature at the current cursor location.
  306.  
  307. - insertSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
  308. {
  309. char *data, *dataptr;
  310. char *signaturefile = sigFile;
  311. char signaturepath[256];
  312. int length, i;
  313. struct stat filestat;
  314. FILE *fpin;
  315.     sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
  316.     if(stat(signaturepath, &filestat))
  317.     {
  318.     data = "";
  319.     length = 0;
  320.     *errmsg = "No signature file found in your home directory.";
  321.     }
  322.     else
  323.     {
  324.     length = filestat.st_size;
  325.     if((fpin = fopen(signaturepath, "r")) != NULL)
  326.     {
  327.         dataptr = data = malloc(length+NUMSIGDASH+10);  /* data remains unchanged */
  328.         for(i=0; i<NUMSIGDASH; i++)        /* Add '---' signature separator here */
  329.         *dataptr++ = '-';
  330.         *dataptr++ = '\n';
  331.         fread((void *)dataptr, 1, length, fpin);
  332.         fclose(fpin);        /* This was missing in V1.0 release */
  333.         *(dataptr+length) = '\0';
  334.         [pbid declareTypes:&NXAsciiPboardType num:1 owner:self];
  335.         [pbid writeType:NXAsciiPboardType data:data length:strlen(data)];
  336.         free(data);
  337.     }
  338.     else
  339.         *errmsg = "Cannot open signature file.";
  340.     }
  341.     return self;
  342. }
  343.  
  344. // Adds the content of ~/.signature.rtf at the current cursor location.
  345. // RTF signature insertion method.
  346. - insertRtfSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
  347. {
  348. char *data;
  349. char *signaturefile = rtfSigFile;
  350. char signaturepath[256];
  351. int length;
  352. struct stat filestat;
  353. FILE *fpin;
  354.     sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
  355.     if(stat(signaturepath, &filestat))
  356.     {
  357.     data = "";
  358.     length = 0;
  359.     *errmsg = "No RTF signature file found in your home directory.";
  360.     }
  361.     else
  362.     {
  363.     length = filestat.st_size;
  364.     if((fpin = fopen(signaturepath, "r")) != NULL)
  365.     {
  366.         data = malloc(length+10);
  367.         fread((void *)data, 1, length, fpin);
  368.         fclose(fpin);
  369.         *(data+length) = '\0';
  370.         [pbid declareTypes:&NXRTFPboardType num:1 owner:self];
  371.         [pbid writeType:NXRTFPboardType data:data length:strlen(data)];
  372.         free(data);
  373.     }
  374.     else
  375.         *errmsg = "Cannot open RTF signature file.";
  376.     }
  377.     return self;
  378. }
  379.  
  380.  
  381. // Adds the content of ~/.signature.rtfd at the current cursor location.
  382. // RTFD signature insertion method.
  383. - insertRtfdSignature:(id)pbid userData:(const char *)udata error:(char **)errmsg
  384. {
  385. char *data;
  386. char *signaturefile = rtfdSigFile;
  387. char signaturepath[256];
  388. int length;
  389. struct stat filestat;
  390.     sprintf(signaturepath, "%s/%s", NXHomeDirectory(), signaturefile);
  391.     if(stat(signaturepath, &filestat))
  392.     {
  393.     data = "";
  394.     length = 0;
  395.     *errmsg = "No RTFD signature found in your home directory.";
  396.     }
  397.     else
  398.     {
  399.     
  400.     if(![gRtfdText openRTFDFrom:signaturepath])
  401.     {
  402.         [tempText selectAll:self];    // This bit of code is necessary because
  403.         [tempText paste:self];    // while Edit, Mail and Text all support RTFD
  404.         [gRtfdText selectAll:self];    // there is as yet no proper NXAtom for the
  405.         [gRtfdText copy:self];    // pasteboard type. So I use the copy and
  406.             [gRtfdText writeSelectionToPasteboard:pbid types:(NXAtom *)[[Pasteboard newName:NXGeneralPboard] types]];
  407.         [tempText selectAll:self];    // to put the text on the general pboard,
  408.         [tempText copy:self];    //from whence I then get the types!
  409.     }
  410.         else
  411.         *errmsg = "Cannot open RTFD signature.";
  412.     }
  413.     return self;
  414. }
  415.  
  416. // quote an RTF selection by graying it out
  417. - grayRTFSelection:(id)pbid userData:(const char *)udata error:(char **)errmsg
  418. {
  419.     NXAtom pbtype[] = {NXRTFPboardType, 0};
  420.     [tempText selectAll:self];
  421.     [tempText readSelectionFromPasteboard:pbid];
  422.     [tempText setSelGray:NX_DKGRAY];
  423.     [tempText writeSelectionToPasteboard:pbid types:pbtype];
  424.     return self;
  425. }
  426.  
  427.  
  428. @end
  429.